package org.starsource.forum.server.dao.test;

import static org.junit.Assert.*;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Date;
import java.util.Set;
import java.sql.Timestamp;

import org.junit.Test;

import org.springframework.beans.factory.annotation.Autowired;

import org.starsource.forum.client.exception.DataNotFoundException;
import org.starsource.forum.client.exception.DatabaseException;
import org.starsource.forum.server.dao.CategoryDao;
import org.starsource.forum.server.dao.MessageDao;
import org.starsource.forum.server.dao.ResourceDao;
import org.starsource.forum.server.dao.SessionDao;
import org.starsource.forum.server.dao.UserDao;
import org.starsource.forum.server.domain.Category;
import org.starsource.forum.server.domain.Message;
import org.starsource.forum.server.domain.Resource;
import org.starsource.forum.server.domain.Session;
import org.starsource.forum.server.domain.User;

public abstract class AbsTestResourceDao {
	protected static org.apache.log4j.Logger logger = org.apache.log4j.LogManager
	.getLogger(AbsTestResourceDao.class.getName());

	@Autowired
	private UserDao userDao;
	
	@Autowired
	private SessionDao sessionDao;

	@Autowired
	private MessageDao messageDao;
	
	@Autowired
	private ResourceDao resourceDao;
	
	@Autowired
	private CategoryDao categoryDao;

	@Test
	public void testSave() throws DatabaseException {
		User user1 = new User("ONLY_FOR_UNIT_TEST", "PASSWORD_FOR_TEST", "NAME_FOR_TEST", "DIRECTORY_FOR_TEST");
		userDao.save(user1);

		Category category1 = new Category(null, "NAME_FOR_UNIT_TEST", "CAPTION_FOR_UNIT_TEST");
		categoryDao.save(category1);
		
		Timestamp createTimestamp, updateTimestamp;
		createTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		try {
			Thread.sleep(1000);			
		} catch (InterruptedException e) {
			fail("Test fail because thread sleep");
		}
		updateTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		Session session1 = new Session(user1, "TITLE_FOR_TEST", category1, createTimestamp, updateTimestamp);
		sessionDao.save(session1);
		
		Message message1 = new Message(1, user1, "CONTENT_FOR_TEST", session1, createTimestamp, updateTimestamp);
		messageDao.save(message1);

		int round = 10;
		Set<Resource> resourceSet1 = new LinkedHashSet<Resource>();
		for(int j = 0; j<round; j++) {
			Resource resource = new Resource(message1, "URL_FOR_TEST" + j, "THUMB_FOR_TEST" + j, j*10, j*100);
			message1.getResources().add(resource);
			resourceDao.save(resource);
			resourceSet1.add(resource);
		}
		
		Iterator<Resource> iterator;
		logger.debug("checking resourceSet1...");
		iterator = resourceSet1.iterator();
		while (iterator.hasNext()) {
			Resource resource = iterator.next();
			logger.debug("id=" + resource.getId() + " url=" + resource.getUrl() + " message_id=" + resource.getMessageId());
		}

		Iterator<Resource> iterator1 = resourceSet1.iterator();
		Set<Resource> resourceSet2 = messageDao.getMessage(message1.getId()).getResources();
		logger.debug("checking resourceSet2...");
		iterator = resourceSet2.iterator();
		while (iterator.hasNext()) {
			Resource resource = iterator.next();
			logger.debug("id=" + resource.getId() + " url=" + resource.getUrl() + " message_id=" + resource.getMessageId());
		}

		logger.debug("resourceSet1.size=" + resourceSet1.size());
		logger.debug("resourceSet2.size=" + resourceSet2.size());
		while (iterator1.hasNext()) {
			Resource resource = iterator1.next();
			Iterator<Resource> iterator2 = resourceSet2.iterator();
			boolean found = false;
			while (iterator2.hasNext()) {
				if (iterator2.next().equals(resource)) {
					found = true;
				}
			}
			assertTrue(found);
		}

		iterator1 = resourceSet2.iterator();
		while (iterator1.hasNext()) {
			Resource resource = iterator1.next();
			Iterator<Resource> iterator2 = resourceSet1.iterator();
			boolean found = false;
			while (iterator2.hasNext()) {
				if (iterator2.next().equals(resource)) {
					found = true;
				}
			}
			assertTrue(found);
		}

	}

	@Test
	public void testUpdate() throws DatabaseException {
		User user1 = new User("ONLY_FOR_UNIT_TEST", "PASSWORD_FOR_TEST", "NAME_FOR_TEST", "DIRECTORY_FOR_TEST");
		userDao.save(user1);
		
		User user2 = new User("ONLY_FOR_UNIT_TEST", "PASSWORD_FOR_TEST", "NAME_FOR_TEST", "DIRECTORY_FOR_TEST");
		userDao.save(user2);

		Category category1 = new Category(null, "NAME_FOR_UNIT_TEST", "CAPTION_FOR_UNIT_TEST");
		categoryDao.save(category1);

		Timestamp createTimestamp, updateTimestamp;
		createTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		try {
			Thread.sleep(1000);			
		} catch (InterruptedException e) {
			fail("Test fail because thread sleep");
		}
		updateTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		Session session1 = new Session(user1, "TITLE_FOR_TEST", category1, createTimestamp, updateTimestamp);
		sessionDao.save(session1);
		
		Session session2 = new Session(user2, "TITLE2_FOR_TEST", category1, createTimestamp, updateTimestamp);
		sessionDao.save(session2);

		Message message1 = new Message(1, user1, "CONTENT_FOR_TEST", session1, createTimestamp, updateTimestamp);
		session1.getMessages().add(message1);
		messageDao.save(message1);
		
		Message message2 = new Message(1, user1, "CONTENT_FOR_TEST", session2, createTimestamp, updateTimestamp);
		session2.getMessages().add(message2);
		messageDao.save(message2);

		Resource resource1 = new Resource(message1, "URL_FOR_TEST", "THUMB_FOR_TEST", 111, 222);
		message1.getResources().add(resource1);
		resourceDao.save(resource1);
		
		resource1.setMessage(message2);
		resource1.setUrl("NEW_URL_FOR_TEST");
		message1.getResources().remove(resource1);
		message2.getResources().add(resource1);
		resourceDao.update(resource1);
		
		Resource resource2 = resourceDao.getResource(resource1.getId());
		assertEquals(resource1, resource2);
	}

	@Test
	public void testDelete() throws DatabaseException {
		User user1 = new User("ONLY_FOR_UNIT_TEST", "PASSWORD_FOR_TEST", "NAME_FOR_TEST", "DIRECTORY_FOR_TEST");
		userDao.save(user1);
		
		Category category1 = new Category(null, "NAME_FOR_UNIT_TEST", "CAPTION_FOR_UNIT_TEST");
		categoryDao.save(category1);

		Timestamp createTimestamp, updateTimestamp;
		createTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		try {
			Thread.sleep(1000);			
		} catch (InterruptedException e) {
			fail("Test fail because thread sleep");
		}
		updateTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		Session session1 = new Session(user1, "TITLE_FOR_TEST", category1, createTimestamp, updateTimestamp);
		sessionDao.save(session1);
		
		Message message1 = new Message(1, user1, "CONTENT_FOR_TEST", session1, createTimestamp, updateTimestamp);
		messageDao.save(message1);
		
		Resource resource1 = new Resource(message1, "URL_FOR_TEST", "THUMB_FOR_TEST", 111, 222);
		message1.getResources().add(resource1);
		resourceDao.save(resource1);
		
		int id = resource1.getId();
		assertNotNull(resourceDao.getResource(id)); 
		resourceDao.delete(resource1);
		try {
			resourceDao.getResource(id);
			assertTrue(false);
		} catch (DataNotFoundException e) {
		}

	}

	@Test
	public void testGetResource() throws DatabaseException {
		User user1 = new User("ONLY_FOR_UNIT_TEST", "PASSWORD_FOR_TEST", "NAME_FOR_TEST", "DIRECTORY_FOR_TEST");
		userDao.save(user1);

		Category category1 = new Category(null, "NAME_FOR_UNIT_TEST", "CAPTION_FOR_UNIT_TEST");
		categoryDao.save(category1);
		
		Timestamp createTimestamp, updateTimestamp;
		createTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		try {
			Thread.sleep(1000);			
		} catch (InterruptedException e) {
			fail("Test fail because thread sleep");
		}
		updateTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		Session session1 = new Session(user1, "TITLE_FOR_TEST", category1, createTimestamp, updateTimestamp);
		sessionDao.save(session1);
		
		Message message1 = new Message(1, user1, "CONTENT_FOR_TEST", session1, createTimestamp, updateTimestamp);
		messageDao.save(message1);

		Resource resource1 = new Resource(message1, "URL_FOR_TEST", "THUMB_FOR_TEST", 111, 222);
		message1.getResources().add(resource1);
		resourceDao.save(resource1);
		
		Resource resource2 = resourceDao.getResource(resource1.getId());
		
		assertEquals(resource1, resource2);
	}

	@Test
	public void testGetResourceSet() throws DatabaseException {
		User user1 = new User("ONLY_FOR_UNIT_TEST", "PASSWORD_FOR_TEST", "NAME_FOR_TEST", "DIRECTORY_FOR_TEST");
		userDao.save(user1);

		Category category1 = new Category(null, "NAME_FOR_UNIT_TEST", "CAPTION_FOR_UNIT_TEST");
		categoryDao.save(category1);
		
		Timestamp createTimestamp, updateTimestamp;
		createTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		try {
			Thread.sleep(1000);			
		} catch (InterruptedException e) {
			fail("Test fail because thread sleep");
		}
		updateTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		Session session1 = new Session(user1, "TITLE_FOR_TEST", category1, createTimestamp, updateTimestamp);
		sessionDao.save(session1);
		
		Message message1 = new Message(1, user1, "CONTENT_FOR_TEST", session1, createTimestamp, updateTimestamp);
		messageDao.save(message1);

		Set<Resource> resourceSet1 = new LinkedHashSet<Resource>();
		for(int index = 0; index < 10; index ++) {
			Resource resource1 = new Resource(message1, "URL_FOR_TEST" + index, "THUMB_FOR_TEST" + index, index * 10, index *100);
			message1.getResources().add(resource1);
			resourceDao.save(resource1);
			resourceSet1.add(resource1);
		}
		
		Set<Resource> resourceSet2 = resourceDao.getResourceSet(message1);
		
		assertTrue(resourceSet1.size() == 10);

		Iterator<Resource> iterator1 = resourceSet1.iterator();
		while (iterator1.hasNext()) {
			Resource resource = iterator1.next();
			Iterator<Resource> iterator2 = resourceSet2.iterator();
			boolean found = false;
			while (iterator2.hasNext()) {
				if (iterator2.next().equals(resource)) {
					found = true;
				}
			}
			assertTrue(found);
		}
		
	}
}
